package top.songxs.gmall.seckill.task;

import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import top.songxs.gmall.seckill.constant.SeckillContant;
import top.songxs.gmall.seckill.entity.SeckillGoods;
import top.songxs.gmall.seckill.service.SeckillGoodsService;

import java.util.Date;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

@Slf4j
@Component
public class CachePreHotTask {


    @Autowired
    private SeckillGoodsService seckillGoodsService;

    public static final ConcurrentHashMap<Long, SeckillGoods> LOCAL_CACHE = new ConcurrentHashMap<>();
    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private RedissonClient redissonClient;



    @Scheduled(cron = "0 0 2 * * ?")
    public void cachePreHotTask() {
        //从数据库中查询到当天参与秒杀的所有商品
        List<SeckillGoods> seckillGoodsList = seckillGoodsService.cachePreHotTask(new Date());
        //将数据缓存到本地缓存中
        CompletableFuture.runAsync(() -> {
            this.flushSeckillGoodsToLocal(seckillGoodsList);
        });
        //将数据缓存到分布式缓存中
        CompletableFuture.runAsync(() -> {
            this.flushSeckillGoodsToRedis(seckillGoodsList);
        });
    }

    //将秒杀商品缓存到本地缓存中
    private void flushSeckillGoodsToLocal(List<SeckillGoods> seckillGoodsList) {
        //清空之前的旧缓存
        LOCAL_CACHE.clear();
        seckillGoodsList.stream().forEach(seckillGoods -> {
            LOCAL_CACHE.put(seckillGoods.getSkuId(), seckillGoods);
        });
    }

    //将秒杀商品缓存到分布式缓存redis中
    private void flushSeckillGoodsToRedis(List<SeckillGoods> seckillGoodsList) {
        RLock lock = redissonClient.getLock(SeckillContant.REDIS_SECKILL_GOODS_LOCK_KEY);
        boolean tryLock = lock.tryLock();
        if (tryLock) {
            try {
                log.info(Thread.currentThread().getName() + "获取到了分布式锁 , 添加秒杀商品数据到Redis中...");
                String redisGoodsKey = seckillGoodsService.buildRedisGoodsKey();
                log.info("刷进redis {}", seckillGoodsList);
                //把数据缓存到redis中
                seckillGoodsList.stream().forEach(goods -> {
                    redisTemplate.opsForHash().put(redisGoodsKey, String.valueOf(goods.getSkuId()), JSON.toJSONString(goods));
                });
                redisTemplate.expire(redisGoodsKey, 2, TimeUnit.DAYS);
            } catch (Exception e) {
                e.printStackTrace();
                throw new RuntimeException(e);
            } finally {
                lock.unlock();
                log.info(Thread.currentThread().getName() + "释放了分布式锁...");
            }
        }
    }
}
